import {
  h,
  PropType,
  defineComponent,
  onMounted,
  onBeforeUnmount,
  ref,
  watch
} from "vue";
import { ECharts, EChartsOption, init } from "echarts";
import { delay, qraf } from "./utils";

export interface OmitedEChartsOption extends EChartsOption {
  graphic?: any;
  options?: OmitedEChartsOption[];
  baseOption?: OmitedEChartsOption;
}

interface IDefaultOptions {
  firstRenderSleep: number;

  clear: boolean;

  renderer: "canvas" | "svg";
}

const DEFAULT_OPTIONS: IDefaultOptions = {
  firstRenderSleep: 0,
  clear: false,
  renderer: (() => {
    const ua = navigator.userAgent.toLowerCase();
    return /mobile/.test(ua) ? "svg" : "canvas";
  })()
};

export interface IChartData {
  chart: ECharts | null;
  sleep: number;
}

export const setFirstRenderSleep = (sleep: number) => {
  DEFAULT_OPTIONS.firstRenderSleep = sleep;
};

export const setClear = (clear: boolean) => {
  DEFAULT_OPTIONS.clear = clear;
};

export const setRenderer = (rendererType: "canvas" | "svg") => {
  DEFAULT_OPTIONS.renderer = rendererType;
};

export const Chart = defineComponent({
  name: "Chart",
  props: {
    options: {
      type: Object as PropType<OmitedEChartsOption>,
      default: () => ({})
    },

    firstRenderSleep: {
      type: Number,
      default: () => DEFAULT_OPTIONS.firstRenderSleep
    },

    clear: {
      type: Boolean,
      default: () => DEFAULT_OPTIONS.clear
    },

    renderer: {
      type: String as PropType<"canvas" | "svg">,
      default: () => DEFAULT_OPTIONS.renderer
    }
  },
  setup(props) {
    let chart = null;
    const sleep = ref<number>(0);
    const el = ref<HTMLDivElement>();
    const renderOptions = async (): Promise<void> => {
      if (!chart) return;
      if (sleep.value > Date.now()) {
        await delay(sleep.value - Date.now());
      }
      qraf.push(() => chart?.setOption(props.options ?? {}));
    };

    const appendTooltipPosition = (
      tooltip: echarts.TooltipComponentOption
    ): void => {
      if (tooltip.position) return;
      tooltip.confine = true;
      tooltip.position = function (_a, _b, el) {
        if (el instanceof HTMLElement) {
          if (el.getBoundingClientRect().left < 0) {
            return "right";
          } else if (
            el.getBoundingClientRect().right >
            window.innerWidth - el.clientWidth
          ) {
            return "left";
          }
        }
        return "inside";
      };
    };
    const onResize = (): void => {
      chart?.resize();
    };

    const onChangeOption = () => {
      if (!chart) return;
      if (props.clear) chart.clear();
      const { tooltip } = props.options;
      if (tooltip) {
        if (tooltip instanceof Array) {
          for (const t of tooltip) appendTooltipPosition(t);
        } else {
          appendTooltipPosition(tooltip);
        }
      }
      renderOptions(); // rerender
    };

    watch(ref(props.options), () => onChangeOption());

    onMounted(() => {
      sleep.value = props.firstRenderSleep + Date.now();
      chart = init(el.value as HTMLDivElement, "default", {
        renderer: props.renderer
      });
      if (props.options) renderOptions();
      window.addEventListener("resize", onResize);
    });

    onBeforeUnmount(() => {
      if (!chart || chart.isDisposed()) return;
      chart.dispose();
      window.removeEventListener("resize", onResize);
    });
    return { el };
  },
  render() {
    return h("div", { ref: "el", class: "chart" });
  }
});
